home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / misc / gs261src.zip / gscoord.c < prev    next >
C/C++ Source or Header  |  1993-05-16  |  10KB  |  345 lines

  1. /* Copyright (C) 1989, 1992 Aladdin Enterprises.  All rights reserved.
  2.  
  3. This file is part of Ghostscript.
  4.  
  5. Ghostscript is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  7. to anyone for the consequences of using it or for whether it serves any
  8. particular purpose or works at all, unless he says so in writing.  Refer
  9. to the Ghostscript General Public License for full details.
  10.  
  11. Everyone is granted permission to copy, modify and redistribute
  12. Ghostscript, but only under the conditions described in the Ghostscript
  13. General Public License.  A copy of this license is supposed to have been
  14. given to you along with Ghostscript so you can know your rights and
  15. responsibilities.  It should be in a file named COPYING.  Among other
  16. things, the copyright notice and this notice must be preserved on all
  17. copies.  */
  18.  
  19. /* gscoord.c */
  20. /* Coordinate system operators for Ghostscript library */
  21. #include "math_.h"
  22. #include "gx.h"
  23. #include "gserrors.h"
  24. #include "gsccode.h"            /* for gxfont.h */
  25. #include "gxarith.h"
  26. #include "gxfixed.h"
  27. #include "gxmatrix.h"
  28. #include "gxfont.h"            /* for char_tm */
  29. #include "gzstate.h"
  30. #include "gzdevice.h"            /* requires gsstate */
  31. #include "gscoord.h"            /* requires gsmatrix, gsstate */
  32.  
  33. /* Choose whether to enable the new rounding code in update_ctm_fixed. */
  34. /* I'm pretty sure this is the right thing to do, but since this change */
  35. /* is being made 1 day before releasing version 2.4, I'm feeling cautious. */
  36. #define round_ctm_fixed 1
  37.  
  38. /* Forward declarations */
  39. #ifdef DEBUG
  40. private void trace_ctm(P1(const gs_state *));
  41. private void trace_matrix(P1(const gs_matrix *));
  42. #endif
  43.  
  44. /* Macro for ensuring ctm_inverse is valid */
  45. #ifdef DEBUG
  46. #define print_inverse(pgs)\
  47. if ( gs_debug['x'] )\
  48.     dprintf("[x]Inverting:\n"), trace_ctm(pgs), trace_matrix(&pgs->ctm_inverse)
  49. #else
  50. #define print_inverse(pgs) 0
  51. #endif
  52. #define ensure_inverse_valid(pgs)\
  53.     if ( !pgs->inverse_valid )\
  54.        {    int code = ctm_set_inverse(pgs);\
  55.         if ( code < 0 ) return code;\
  56.        }
  57.  
  58. private int
  59. ctm_set_inverse(gs_state *pgs)
  60. {    int code = gs_matrix_invert(&ctm_only(pgs), &pgs->ctm_inverse);
  61.     print_inverse(pgs);
  62.     if ( code < 0 ) return code;
  63.     pgs->inverse_valid = 1;
  64.     return 0;
  65. }
  66.  
  67. /* Machinery for updating fixed version of ctm. */
  68. /*
  69.  * We (conditionally) adjust the floating point translation
  70.  * so that it exactly matches the (rounded) fixed translation.
  71.  * This avoids certain unpleasant rounding anomalies, such as
  72.  * 0 0 moveto currentpoint not returning 0 0, and () stringwidth
  73.  * not returning 0 0.
  74.  */
  75. #if round_ctm_fixed            /* ****** NOTA BENE ****** */
  76. #  define update_t_fixed(mat, t, t_fixed)\
  77.     (mat).t = fixed2float((mat).t_fixed = float2fixed((mat).t))
  78. #else                    /* !round_update_fixed */
  79. #  define update_t_fixed(mat, t, t_fixed)\
  80.     (mat).t_fixed = float2fixed((mat).t)
  81. #endif                    /* (!)round_update_fixed */
  82. #define update_matrix_fixed(mat)\
  83.   update_t_fixed(mat, tx, tx_fixed),\
  84.   update_t_fixed(mat, ty, ty_fixed)
  85. #define update_ctm(pgs)\
  86.   update_matrix_fixed(pgs->ctm),\
  87.   pgs->inverse_valid = 0,\
  88.   pgs->char_tm_valid = 0
  89.  
  90. void
  91. gs_update_matrix_fixed(gs_matrix_fixed *pmat)
  92. {    update_matrix_fixed(*pmat);
  93. }
  94.  
  95. /* ------ Coordinate system definition ------ */
  96.  
  97. int
  98. gs_initmatrix(gs_state *pgs)
  99. {    gx_device *dev = pgs->device->info;
  100.     (*dev->procs->get_initial_matrix)(dev, &ctm_only(pgs));
  101.     update_ctm(pgs);
  102. #ifdef DEBUG
  103. if ( gs_debug['x'] )
  104.     dprintf("[x]initmatrix:\n"), trace_ctm(pgs);
  105. #endif
  106.     return 0;
  107. }
  108.  
  109. int
  110. gs_defaultmatrix(const gs_state *pgs, gs_matrix *pmat)
  111. {    gx_device *dev = pgs->device->info;
  112.     (*dev->procs->get_initial_matrix)(dev, pmat);
  113.     return 0;
  114. }
  115.  
  116. int
  117. gs_currentmatrix(const gs_state *pgs, gs_matrix *pmat)
  118. {    *pmat = ctm_only(pgs);
  119.     return 0;
  120. }
  121.  
  122. /* Read (after possibly computing) the current transformation matrix */
  123. /* for rendering text.  If force=1, update char_tm if it is invalid; */
  124. /* if force=0, don't update char_tm, and return an error code. */
  125. int
  126. gs_currentcharmatrix(gs_state *pgs, gs_matrix *ptm, int force)
  127. {    if ( !pgs->char_tm_valid )
  128.     {    int code;
  129.         if ( !force )
  130.             return gs_error_undefinedresult;
  131.         /* Compute combined transformation */
  132.         gs_make_identity(&char_tm_only(pgs));    /* make sure type */
  133.                     /* fields are set in char_tm! */
  134.         code = gs_matrix_multiply(&pgs->font->FontMatrix,
  135.                       &ctm_only(pgs), &char_tm_only(pgs));
  136.         if ( code < 0 )
  137.             return code;
  138.         gs_update_matrix_fixed(&pgs->char_tm);
  139.         pgs->char_tm_valid = 1;
  140.     }
  141.     if ( ptm != NULL )
  142.         *ptm = char_tm_only(pgs);
  143.     return 0;
  144. }
  145.  
  146. int
  147. gs_setmatrix(gs_state *pgs, const gs_matrix *pmat)
  148. {    ctm_only(pgs) = *pmat;
  149.     update_ctm(pgs);
  150. #ifdef DEBUG
  151. if ( gs_debug['x'] )
  152.     dprintf("[x]setmatrix:\n"), trace_ctm(pgs);
  153. #endif
  154.     return 0;
  155. }
  156.  
  157. int
  158. gs_translate(gs_state *pgs, floatp dx, floatp dy)
  159. {    gs_point pt;
  160.     int code;
  161.     if ( (code = gs_distance_transform(dx, dy, &ctm_only(pgs), &pt)) < 0 )
  162.         return code;
  163.     pgs->ctm.tx += pt.x;
  164.     pgs->ctm.ty += pt.y;
  165.     update_ctm(pgs);
  166. #ifdef DEBUG
  167. if ( gs_debug['x'] )
  168.     dprintf4("[x]translate: %f %f -> %f %f\n",
  169.          dx, dy, pt.x, pt.y),
  170.     trace_ctm(pgs);
  171. #endif
  172.     return 0;
  173. }
  174.  
  175. int
  176. gs_scale(gs_state *pgs, floatp sx, floatp sy)
  177. {    pgs->ctm.xx *= sx;
  178.     pgs->ctm.xy *= sx;
  179.     pgs->ctm.yx *= sy;
  180.     pgs->ctm.yy *= sy;
  181.     pgs->inverse_valid = 0, pgs->char_tm_valid = 0;
  182. #ifdef DEBUG
  183. if ( gs_debug['x'] )
  184.     dprintf2("[x]scale: %f %f\n", sx, sy), trace_ctm(pgs);
  185. #endif
  186.     return 0;
  187. }
  188.  
  189. int
  190. gs_rotate(gs_state *pgs, floatp ang)
  191. {    int code = gs_matrix_rotate(&ctm_only(pgs), ang, &ctm_only(pgs));
  192.     pgs->inverse_valid = 0, pgs->char_tm_valid = 0;
  193. #ifdef DEBUG
  194. if ( gs_debug['x'] )
  195.     dprintf1("[x]rotate: %f\n", ang), trace_ctm(pgs);
  196. #endif
  197.     return code;
  198. }
  199.  
  200. int
  201. gs_concat(gs_state *pgs, const gs_matrix *pmat)
  202. {    int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &ctm_only(pgs));
  203.     update_ctm(pgs);
  204. #ifdef DEBUG
  205. if ( gs_debug['x'] )
  206.     dprintf("[x]concat:\n"), trace_matrix(pmat), trace_ctm(pgs);
  207. #endif
  208.     return code;
  209. }
  210.  
  211. /* ------ Coordinate transformation ------ */
  212.  
  213. int
  214. gs_transform(gs_state *pgs, floatp x, floatp y, gs_point *pt)
  215. {    return gs_point_transform(x, y, &ctm_only(pgs), pt);
  216. }
  217.  
  218. int
  219. gs_dtransform(gs_state *pgs, floatp dx, floatp dy, gs_point *pt)
  220. {    return gs_distance_transform(dx, dy, &ctm_only(pgs), pt);
  221. }
  222.  
  223. int
  224. gs_itransform(gs_state *pgs, floatp x, floatp y, gs_point *pt)
  225. {    /* If the matrix isn't skewed, we get more accurate results */
  226.     /* by using transform_inverse than by using the inverse matrix. */
  227.     if ( !is_skewed(&pgs->ctm) )
  228.        {    return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt);
  229.        }
  230.     else
  231.        {    ensure_inverse_valid(pgs);
  232.         return gs_point_transform(x, y, &pgs->ctm_inverse, pt);
  233.        }
  234. }
  235.  
  236. int
  237. gs_idtransform(gs_state *pgs, floatp dx, floatp dy, gs_point *pt)
  238. {    /* If the matrix isn't skewed, we get more accurate results */
  239.     /* by using transform_inverse than by using the inverse matrix. */
  240.     if ( !is_skewed(&pgs->ctm) )
  241.        {    return gs_distance_transform_inverse(dx, dy,
  242.                              &ctm_only(pgs), pt);
  243.        }
  244.     else
  245.        {    ensure_inverse_valid(pgs);
  246.         return gs_distance_transform(dx, dy, &pgs->ctm_inverse, pt);
  247.        }
  248. }
  249.  
  250. /* ------ For internal use only ------ */
  251.  
  252. /* Set the translation to a fixed value, */
  253. /* translate any existing path, and mark char_tm as valid. */
  254. /* Used by gschar.c to prepare for a BuildChar or BuildGlyph procedure. */
  255. int
  256. gs_translate_to_fixed(register gs_state *pgs, fixed px, fixed py)
  257. {    fixed dx = px - pgs->ctm.tx_fixed;
  258.     fixed dy = py - pgs->ctm.ty_fixed;
  259.     gx_path_translate(pgs->path, dx, dy);
  260.     pgs->ctm.tx = fixed2float(pgs->ctm.tx_fixed = px);
  261.     pgs->ctm.ty = fixed2float(pgs->ctm.ty_fixed = py);
  262.     pgs->inverse_valid = 0;
  263.     pgs->char_tm_valid = 1;
  264.     return 0;
  265. }
  266.  
  267. /* Compute the coefficients for fast fixed-point distance transformations */
  268. /* from a transformation matrix. */
  269. /* We should cache the coefficients with the ctm.... */
  270. int
  271. gx_matrix_to_fixed_coeff(const gs_matrix *pmat, register fixed_coeff *pfc,
  272.   int max_bits)
  273. {    gs_matrix ctm;
  274.     int scale = -10000;
  275.     int expt, shift;
  276.     ctm = *pmat;
  277.     pfc->skewed = 0;
  278.     if ( !is_fzero(ctm.xx) )
  279.        {    (void)frexp(ctm.xx, &scale);
  280.        }
  281.     if ( !is_fzero(ctm.xy) )
  282.        {    (void)frexp(ctm.xy, &expt);
  283.         if ( expt > scale ) scale = expt;
  284.         pfc->skewed = 1;
  285.        }
  286.     if ( !is_fzero(ctm.yx) )
  287.        {    (void)frexp(ctm.yx, &expt);
  288.         if ( expt > scale ) scale = expt;
  289.         pfc->skewed = 1;
  290.        }
  291.     if ( !is_fzero(ctm.yy) )
  292.        {    (void)frexp(ctm.yy, &expt);
  293.         if ( expt > scale ) scale = expt;
  294.        }
  295.     scale = sizeof(long) * 8 - 1 - max_bits - scale;
  296.     shift = scale - _fixed_shift;
  297.     if ( shift > 0 )
  298.        {    pfc->shift = shift;
  299.         pfc->round = (fixed)1 << (shift - 1);
  300.        }
  301.     else
  302.        {    pfc->shift = 0;
  303.         pfc->round = 0;
  304.         scale -= shift;
  305.        }
  306. #define set_c(c)\
  307.   if ( is_fzero(ctm.c) ) pfc->c.f = 0, pfc->c.l = 0;\
  308.   else pfc->c.f = ldexp(ctm.c, _fixed_shift), pfc->c.l = (long)ldexp(ctm.c, scale)
  309.     set_c(xx);
  310.     set_c(xy);
  311.     set_c(yx);
  312.     set_c(yy);
  313. #ifdef DEBUG
  314. if ( gs_debug['x'] )
  315.    {    dprintf7("[x]ctm: [%6g %6g %6g %6g ; %6g %6g] scale=%d\n",
  316.          ctm.xx, ctm.xy, ctm.yx, ctm.yy, ctm.tx, ctm.ty, scale);
  317.     dprintf5("   fc: [%lx %lx %lx %lx] shift=%d\n",
  318.          pfc->xx, pfc->xy, pfc->yx, pfc->yy,
  319.          pfc->shift);
  320.    }
  321. #endif
  322.     pfc->max_bits = max_bits;
  323.     return 0;
  324. }
  325.  
  326. /* ------ Debugging printout ------ */
  327.  
  328. #ifdef DEBUG
  329.  
  330. /* Print a matrix */
  331. private void
  332. trace_ctm(const gs_state *pgs)
  333. {    const gs_matrix_fixed *pmat = &pgs->ctm;
  334.     trace_matrix((gs_matrix *)pmat);
  335.     dprintf2("\t\tt_fixed: [%6g %6g]\n",
  336.          fixed2float(pmat->tx_fixed), fixed2float(pmat->ty_fixed));
  337. }
  338. private void
  339. trace_matrix(register const gs_matrix *pmat)
  340. {    dprintf6("\t[%6g %6g %6g %6g %6g %6g]\n",
  341.          pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
  342. }
  343.  
  344. #endif
  345.